package engine.math
{
	import engine.core.*;
	
	import flash.geom.*;
	
	public class RxMatrix4x4
	{
		public var m00:Number;
		public var m01:Number;
		public var m02:Number;
		public var m03:Number;
		public var m10:Number;
		public var m11:Number;
		public var m12:Number;
		public var m13:Number;
		public var m20:Number;
		public var m21:Number;
		public var m22:Number;
		public var m23:Number;
		public var m30:Number;
		public var m31:Number;
		public var m32:Number;
		public var m33:Number;
		private static var s_tmp0:RxMatrix4x4 = new RxMatrix4x4;
		private static var s_tmp1:RxMatrix4x4 = new RxMatrix4x4;
		private static var s_pool:RxObjectPool = null;
		
		public function RxMatrix4x4()
		{
			this.m00 = 1;
			this.m01 = 0;
			this.m02 = 0;
			this.m03 = 0;
			this.m10 = 0;
			this.m11 = 1;
			this.m12 = 0;
			this.m13 = 0;
			this.m20 = 0;
			this.m21 = 0;
			this.m22 = 1;
			this.m23 = 0;
			this.m30 = 0;
			this.m31 = 0;
			this.m32 = 0;
			this.m33 = 1;
		}
		
		public static function CreatePool(initSize:uint, growSize:uint) : void
		{
			var allocFunc:Function = function () : Object
			{
				return new RxMatrix4x4();
			};
			
			s_pool = new RxObjectPool(allocFunc, null, initSize, growSize, RxMatrix4x4);
		}
		
		public function Identity() : void
		{
			this.m00 = 1;
			this.m01 = 0;
			this.m02 = 0;
			this.m03 = 0;
			this.m10 = 0;
			this.m11 = 1;
			this.m12 = 0;
			this.m13 = 0;
			this.m20 = 0;
			this.m21 = 0;
			this.m22 = 1;
			this.m23 = 0;
			this.m30 = 0;
			this.m31 = 0;
			this.m32 = 0;
			this.m33 = 1;
		}
		
		public static function PoolAlloc() : RxMatrix4x4
		{
			return RxMatrix4x4(s_pool.Alloc());
		}
		
		public static function PoolFree(matrix:RxMatrix4x4) : void
		{
			s_pool.Free(matrix);
		}
		
		public function ViewFromRotations(vector:RxVector4, x:Number, vector3:Number, param4:Number) : void
		{
			s_tmp1.RotateX(x);
			s_tmp1.PostMulRotateY(vector3);
			s_tmp1.PostMulRotateZ(param4);
			
			var vector1:* = RxVector4.PoolAlloc();
			var vector2:* = RxVector4.PoolAlloc();
			vector1.x = s_tmp1.m10;
			vector1.y = s_tmp1.m11;
			vector1.z = s_tmp1.m12;
			vector1.w = 0;
			vector2.x = s_tmp1.m20;
			vector2.y = s_tmp1.m21;
			vector2.z = s_tmp1.m22;
			vector2.w = 0;
			this.View(vector, vector2, vector1);
			RxVector4.PoolFree(vector1);
			RxVector4.PoolFree(vector2);
		}
		
		public function RotateX(value:Number) : void
		{
			var sin:Number = NaN;
			var cos:Number = NaN;
			sin = Math.sin(value);
			cos = Math.cos(value);
			this.RotateXSinCos(sin, cos);
		}
		
		public function RotateXSinCos(m12_21:Number, m11_22:Number) : void
		{
			this.m00 = 1;
			this.m01 = 0;
			this.m02 = 0;
			this.m03 = 0;
			this.m10 = 0;
			this.m11 = m11_22;
			this.m12 = m12_21;
			this.m13 = 0;
			this.m20 = 0;
			this.m21 = -m12_21;
			this.m22 = m11_22;
			this.m23 = 0;
			this.m30 = 0;
			this.m31 = 0;
			this.m32 = 0;
			this.m33 = 1;
		}
		
		public function PostMulRotateY(value:Number) : void
		{
			var sin:Number = NaN;
			var cos:Number = NaN;
			sin = Math.sin(value);
			cos = Math.cos(value);
			this.PostMulRotateYSinCos(sin, cos);
		}
		
		public function PostMulRotateYSinCos(sin:Number, cos:Number) : void
		{
			this.m00 = this.m00 * cos + this.m02 * sin;
			this.m02 = this.m02 * cos - this.m00 * sin;
			this.m10 = this.m10 * cos + this.m12 * sin;
			this.m12 = this.m12 * cos - this.m10 * sin;
			this.m20 = this.m20 * cos + this.m22 * sin;
			this.m22 = this.m22 * cos - this.m20 * sin;
			this.m30 = this.m30 * cos + this.m32 * sin;
			this.m32 = this.m32 * cos - this.m30 * sin;
		}
		
		public function PostMulRotateZ(value:Number) : void
		{
			var sin:Number = NaN;
			var cos:Number = NaN;
			sin = Math.sin(value);
			cos = Math.cos(value);
			this.PostMulRotateZSinCos(sin, cos);
		}
		
		public function PostMulRotateZSinCos(sin:Number, cos:Number) : void
		{
			this.m00 = this.m00 * cos - this.m01 * sin;
			this.m01 = this.m00 * sin + this.m01 * cos;
			this.m10 = this.m10 * cos - this.m11 * sin;
			this.m11 = this.m10 * sin + this.m11 * cos;
			this.m20 = this.m20 * cos - this.m21 * sin;
			this.m21 = this.m20 * sin + this.m21 * cos;
			this.m30 = this.m30 * cos - this.m31 * sin;
			this.m31 = this.m30 * sin + this.m31 * cos;
		}
		
		public function View(vector1:RxVector4, vector2:RxVector4, vector3:RxVector4) : void
		{
			var vector4:* = RxVector4.PoolAlloc();
			RxVector4.CrossProduct3(vector4, vector3, vector2);
			this.m00 = vector4.x;
			this.m01 = vector3.x;
			this.m02 = vector2.x;
			this.m03 = 0;
			this.m10 = vector4.y;
			this.m11 = vector3.y;
			this.m12 = vector2.y;
			this.m13 = 0;
			this.m20 = vector4.z;
			this.m21 = vector3.z;
			this.m22 = vector2.z;
			this.m23 = 0;
			this.m30 = (-vector1.x) * this.m00 - vector1.y * this.m10 - vector1.z * this.m20;
			this.m31 = (-vector1.x) * this.m01 - vector1.y * this.m11 - vector1.z * this.m21;
			this.m32 = (-vector1.x) * this.m02 - vector1.y * this.m12 - vector1.z * this.m22;
			this.m33 = 1;
			RxVector4.PoolFree(vector4);
		}
		
		public static function Mul4x4(param1:RxMatrix4x4, param2:RxMatrix4x4, param3:RxMatrix4x4) : void
		{
			var _loc_4:* = param2.m00 * param3.m00 + param2.m01 * param3.m10 + param2.m02 * param3.m20 + param2.m03 * param3.m30;
			var _loc_5:* = param2.m00 * param3.m01 + param2.m01 * param3.m11 + param2.m02 * param3.m21 + param2.m03 * param3.m31;
			var _loc_6:* = param2.m00 * param3.m02 + param2.m01 * param3.m12 + param2.m02 * param3.m22 + param2.m03 * param3.m32;
			var _loc_7:* = param2.m00 * param3.m03 + param2.m01 * param3.m13 + param2.m02 * param3.m23 + param2.m03 * param3.m33;
			var _loc_8:* = param2.m10 * param3.m00 + param2.m11 * param3.m10 + param2.m12 * param3.m20 + param2.m13 * param3.m30;
			var _loc_9:* = param2.m10 * param3.m01 + param2.m11 * param3.m11 + param2.m12 * param3.m21 + param2.m13 * param3.m31;
			var _loc_10:* = param2.m10 * param3.m02 + param2.m11 * param3.m12 + param2.m12 * param3.m22 + param2.m13 * param3.m32;
			var _loc_11:* = param2.m10 * param3.m03 + param2.m11 * param3.m13 + param2.m12 * param3.m23 + param2.m13 * param3.m33;
			var _loc_12:* = param2.m20 * param3.m00 + param2.m21 * param3.m10 + param2.m22 * param3.m20 + param2.m23 * param3.m30;
			var _loc_13:* = param2.m20 * param3.m01 + param2.m21 * param3.m11 + param2.m22 * param3.m21 + param2.m23 * param3.m31;
			var _loc_14:* = param2.m20 * param3.m02 + param2.m21 * param3.m12 + param2.m22 * param3.m22 + param2.m23 * param3.m32;
			var _loc_15:* = param2.m20 * param3.m03 + param2.m21 * param3.m13 + param2.m22 * param3.m23 + param2.m23 * param3.m33;
			var _loc_16:* = param2.m30 * param3.m00 + param2.m31 * param3.m10 + param2.m32 * param3.m20 + param2.m33 * param3.m30;
			var _loc_17:* = param2.m30 * param3.m01 + param2.m31 * param3.m11 + param2.m32 * param3.m21 + param2.m33 * param3.m31;
			var _loc_18:* = param2.m30 * param3.m02 + param2.m31 * param3.m12 + param2.m32 * param3.m22 + param2.m33 * param3.m32;
			var _loc_19:* = param2.m30 * param3.m03 + param2.m31 * param3.m13 + param2.m32 * param3.m23 + param2.m33 * param3.m33;
			param1.m00 = _loc_4;
			param1.m01 = _loc_5;
			param1.m02 = _loc_6;
			param1.m03 = _loc_7;
			param1.m10 = _loc_8;
			param1.m11 = _loc_9;
			param1.m12 = _loc_10;
			param1.m13 = _loc_11;
			param1.m20 = _loc_12;
			param1.m21 = _loc_13;
			param1.m22 = _loc_14;
			param1.m23 = _loc_15;
			param1.m30 = _loc_16;
			param1.m31 = _loc_17;
			param1.m32 = _loc_18;
			param1.m33 = _loc_19;
		}
		
		public function OrthoCenteredRightHanded(param1:Number, param2:Number, param3:Number, param4:Number, param5:Boolean) : void
		{
			var _loc_6:* = 0.5 * param1;
			var _loc_7:* = 0.5 * param2;
			this.OrthoRightHanded(-_loc_6, _loc_6, -_loc_7, _loc_7, param3, param4, param5);
		}
		
		public function OrthoRightHanded(param1:Number, param2:Number, param3:Number, param4:Number, param5:Number, param6:Number, param7:Boolean) : void
		{
			if (param7)
			{
				this.m00 = 2 / (param2 - param1);
				this.m01 = 0;
				this.m02 = 0;
				this.m03 = 0;
				this.m10 = 0;
				this.m11 = 2 / (param4 - param3);
				this.m12 = 0;
				this.m13 = 0;
				this.m20 = 0;
				this.m21 = 0;
				this.m22 = -1 / (param6 - param5);
				this.m23 = 0;
				this.m30 = (-(param2 + param1)) / (param2 - param1);
				this.m31 = (-(param4 + param3)) / (param4 - param3);
				this.m32 = (-param5) / (param6 - param5);
				this.m33 = 1;
			}
			else
			{
				this.m00 = 2 / (param2 - param1);
				this.m01 = 0;
				this.m02 = 0;
				this.m03 = 0;
				this.m10 = 0;
				this.m11 = 2 / (param4 - param3);
				this.m12 = 0;
				this.m13 = 0;
				this.m20 = 0;
				this.m21 = 0;
				this.m22 = -2 / (param6 - param5);
				this.m23 = 0;
				this.m30 = (-(param2 + param1)) / (param2 - param1);
				this.m31 = (-(param4 + param3)) / (param4 - param3);
				this.m32 = (-(param6 + param5)) / (param6 - param5);
				this.m33 = 1;
			}
		}
		
		public function PostMulTranslate(param1:Number, param2:Number, param3:Number) : void
		{
			this.m00 = this.m00 + this.m03 * param1;
			this.m01 = this.m01 + this.m03 * param2;
			this.m02 = this.m02 + this.m03 * param3;
			this.m10 = this.m10 + this.m13 * param1;
			this.m11 = this.m11 + this.m13 * param2;
			this.m12 = this.m12 + this.m13 * param3;
			this.m20 = this.m20 + this.m23 * param1;
			this.m21 = this.m21 + this.m23 * param2;
			this.m22 = this.m22 + this.m23 * param3;
			this.m30 = this.m30 + this.m33 * param1;
			this.m31 = this.m31 + this.m33 * param2;
			this.m32 = this.m32 + this.m33 * param3;
		}
		
		public function PostMulScale(param1:Number, param2:Number, param3:Number) : void
		{
			this.m00 = this.m00 * param1;
			this.m01 = this.m01 * param2;
			this.m02 = this.m02 * param3;
			this.m10 = this.m10 * param1;
			this.m11 = this.m11 * param2;
			this.m12 = this.m12 * param3;
			this.m20 = this.m20 * param1;
			this.m21 = this.m21 * param2;
			this.m22 = this.m22 * param3;
			this.m30 = this.m30 * param1;
			this.m31 = this.m31 * param2;
			this.m32 = this.m32 * param3;
		}
		
		public function Copy(param1:RxMatrix4x4) : void
		{
			this.m00 = param1.m00;
			this.m01 = param1.m01;
			this.m02 = param1.m02;
			this.m03 = param1.m03;
			this.m10 = param1.m10;
			this.m11 = param1.m11;
			this.m12 = param1.m12;
			this.m13 = param1.m13;
			this.m20 = param1.m20;
			this.m21 = param1.m21;
			this.m22 = param1.m22;
			this.m23 = param1.m23;
			this.m30 = param1.m30;
			this.m31 = param1.m31;
			this.m32 = param1.m32;
			this.m33 = param1.m33;
		}
	}
}